/*
 * Class Client:
 * 
 * This is the GUI manager.  It controls turns, and tells the player/AI when they can and can't
 * make a move.
 */

/**
 *
 * @author Jill Greczek, Julio Montero, Brandon Jarratt
 */

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

import java.awt.Color;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;


class Client extends JFrame implements ActionListener
{
	/** The dimensions of the frame */
	private static final int width = 600;
	private static final int height = 600;
	
	/** The game that is played */
	Game game;

	/** The current TURN */
	Player current;
	

	/** Initialize the JFrame */
	public void frameInit()
	{
		addWindowListener(new WindowAdapter()
		{
			public void windowClosing(WindowEvent e)
			{
				System.out.println("Closing normally...");
				System.exit(0);
			}
		});	
		
		setTitle("Othello System");
		setSize(width, height);
		setResizable(false);
		setLocation(100,100);
		
		initGUI();
		setVisible(true);
		newGame();
	}

	/** Represents the array of spaces on the board */
	JButton[][] buttons;
	
	/** Player scores */
	JLabel scoreW;
	JLabel scoreB;
	
	/** Displays the LearningAI message */
	JTextArea messageLog;
	
	/** Initializes the GUI */
	public void initGUI()
	{
		System.out.print("Initialing GUI....");
		
		// Main JFrame layout setup
		// Use a GridBagLayout to organize components
		setLayout(new GridBagLayout());
		GridBagConstraints manager = new GridBagConstraints();	
		manager.fill = GridBagConstraints.BOTH;
		manager.weighty = .80;
		
		JPanel board = new JPanel();
		board.setBorder(BorderFactory.createCompoundBorder
				(BorderFactory.createCompoundBorder(
				 BorderFactory.createTitledBorder("Game Board"),
				 BorderFactory.createEmptyBorder(5,5,5,5)), 
				 board.getBorder()));
		manager.gridx = 0;
		manager.gridy = 0;
		manager.weightx = .75;
		add(board, manager);
		
		JPanel status = new JPanel();
		status.setBorder(BorderFactory.createCompoundBorder
				(BorderFactory.createCompoundBorder(
				 BorderFactory.createTitledBorder("Game Status"),
				 BorderFactory.createEmptyBorder(5,5,5,5)), 
				 status.getBorder()));
		manager.gridx = 1;
		manager.weightx = .25;
		add(status, manager);
		
		/** The learning AI will display messages here. */
		messageLog = new JTextArea("AI messages will be displayed here.");
		messageLog.setEditable(false);
		messageLog.setWrapStyleWord(true);
		messageLog.setLineWrap(true);
		
		JScrollPane logScroller = new JScrollPane(messageLog);
		logScroller.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
		logScroller.setBorder(BorderFactory.createCompoundBorder
							(BorderFactory.createCompoundBorder(
							 BorderFactory.createTitledBorder("AI Message Log"),
							 BorderFactory.createEmptyBorder(5,5,5,5)), 
							 logScroller.getBorder()));
		manager.gridx = 0;
		manager.gridy = 1;
		manager.gridwidth = GridBagConstraints.REMAINDER;
		manager.weighty = .20;
		add(logScroller, manager);
		
		// Reset the layout manager for the game board panel
		board.setLayout(new GridBagLayout());
		manager = new GridBagConstraints();
		manager.gridx = 0;
		manager.gridy = 0;
		manager.weightx = .125;
		manager.weighty = .125;
		manager.fill = GridBagConstraints.BOTH;
		
		buttons = new JButton[8][8];
		for(int i = 0; i < buttons.length; i++)
		{
			for(int j = 0; j < buttons[i].length; j++)
			{
				JButton temp = new JButton();
				temp.setActionCommand(i + "_" + j);
				temp.addActionListener(this);
				temp.setEnabled(true);
				buttons[i][j] = temp;
				board.add(temp, manager);
				manager.gridx++;
			}
			manager.gridx = 0;
			manager.gridy++;
		}
		
		
		// Reset the layout manager for the status panel
		status.setLayout(new GridBagLayout());
		manager = new GridBagConstraints();
		
		JButton newGameButton = new JButton("New Game");
		newGameButton.setActionCommand("NEW");
		newGameButton.addActionListener(this);
		manager.weightx = .5;
		manager.weighty = .5;
		status.add(newGameButton, manager);
		
		scoreW = new JLabel("White:            ");
		manager.gridx = 0;
		manager.gridy = 1;
		status.add(scoreW, manager);
		
		scoreB = new JLabel("Black:          ");
		manager.gridx = 0;
		manager.gridy = 2;
		status.add(scoreB, manager);
		
		System.out.println("..complete.");
	}
	
	/** This method handles the player clicking a button */
	public void actionPerformed(ActionEvent e)
	{
		String command = e.getActionCommand();
		//Start a new game
		if(command == "NEW")
			newGameRequest();
		else
		{
			//Handle the player input
			int[] move = new int[2];
			move[0] = Integer.parseInt(command.substring(0,1));
			move[1] = Integer.parseInt(command.substring(2,3));
			System.out.println("Player attempts a move at " + move[0] + "_" + move[1]);
			//This method updates the board state based on the player's move
			game.updateMinimax(move, current);
			disableButtons();
			updateScore();
			messageLog.append("\n\nPlayer attempts a move at " + move[0] + "_" + move[1]);
			//This drawButtons() call seems redundant but we need it in case
			//the computer runs out of moves to make.
			drawButtons();
			nextTurn();	
			compTurn();
		}
	}
	
	/** This method handles the user clicking a new game */
	public void newGameRequest()
	{
		// creates a basic JOptionPane request
		int n = JOptionPane.showConfirmDialog(
		    this,
		    "Do you really want to start a new game?",
		    "New Game Request",
		    JOptionPane.YES_NO_OPTION);
		if(n == 0)
			newGame();
	}
	
	/** Start a new game */
	public void newGame()
	{
		//Select a Color
		Player[] colors = {Player.WHITE, Player.BLACK};
		Object c = JOptionPane.showInputDialog(
							this,
							"Select your color",
							"Color",
							JOptionPane.QUESTION_MESSAGE,
							null,
							colors,
							Player.WHITE);
		Player player_color = (Player)c;
		
		// If user hits cancel or the X, do nothing.
		if(player_color == null)
			if(game == null)
				System.exit(0);
			else
				return;
		
		
		Color color = Color.white;
		if(player_color == Player.WHITE)
		{
			player_color = Player.BLACK;
			color = Color.black;
		}
		else if(player_color == Player.BLACK)
		{
			player_color = Player.WHITE;
			color = Color.white;
		}

		//Select a Difficulty
		Object[] levels = {Difficulty.EASY, Difficulty.MEDIUM, Difficulty.HARD, "LEARNING AI"};
		Object d = JOptionPane.showInputDialog(
		                    this,
		                    "Select your difficulty",
		                    "Difficulty Select",
		                    JOptionPane.PLAIN_MESSAGE,
		                    null,
		                    levels,
		                    Difficulty.MEDIUM);
		//Learning AI initialization
		if(d == "LEARNING AI")
		{
			game = new Game(player_color);
			game.getLearningAI().setTextArea(messageLog);
			messageLog.append("\n\nAI difficulty set to learning.");
			clearBoard(new Color(210, 255, 255));
		}
		else
		{
			//Regular AI initialization
			Difficulty level = (Difficulty) d;
			if(level == null)
				if(game == null)
					System.exit(0);
				else
					return;
		
			game = new Game(player_color, level);
			messageLog.append("\n\nAI difficulty set to " + level);
			
			if(level == Difficulty.EASY)
				clearBoard(new Color(111, 253, 245));
			else if(level == Difficulty.MEDIUM)
				clearBoard(Color.pink);
			else if(level == Difficulty.HARD)
				clearBoard(color);
		}
		firstTurn(player_color);
	}
	
	/** Makes black go first */
	public void firstTurn(Player color)
	{
		current = Player.BLACK;
		if(color == Player.WHITE)
			playerTurn();
		else
			compTurn();
	}
	
	/** Handles the player's turn */
	public void playerTurn()
	{
		drawButtons();
		if(game.gameOver())
			gameOver();
		else
			allowMove();
	}
	
	/** Handles the AI's turn */
	public void compTurn()
	{
		if(game.gameOver())
			gameOver();
		else
		{
			drawButtons();
			game.makeMove(game.getState());
			nextTurn();
			updateScore();
			playerTurn();
		}
	}
	
	/** Changes the color of who's turn it is */
	public void nextTurn()
	{
		if(current == Player.BLACK)
			current = Player.WHITE;
		else if(current == Player.WHITE)
			current = Player.BLACK;
	}
	
	/** Updates the score after a turn */
	public void updateScore()
	{
		scoreW.setText("White: " + game.getScore(Player.WHITE));
		scoreB.setText("Black: " + game.getScore(Player.BLACK));
	}
	
	/** Executed once the game over qualifications are met */
	public void gameOver()
	{
		disableButtons();
		if(game.winner() == Player.WHITE)
		{
			JOptionPane.showMessageDialog(this, "White wins!");
			messageLog.append("\n\nWhite wins the game.");

		}
		else if(game.winner() == Player.BLACK)
		{
			JOptionPane.showMessageDialog(this, "Black wins!");
			messageLog.append("\n\nBlack wins the game.");
		}
		else
		{
			JOptionPane.showMessageDialog(this, "The game ended in a draw.");
			messageLog.append("\n\nTie game.");
		}
	}
	
	/** Displays the buttons on the screen */
	public void drawButtons()
	{
		Player[][] state = game.getState();
		for(int i = 0; i < state.length; i++)
			for(int j = 0; j < state[i].length; j++)
			{
				if(state[i][j] == Player.BLACK)
					buttons[i][j].setBackground(Color.black);
				else if(state[i][j] == Player.WHITE)
					buttons[i][j].setBackground(Color.white);
			}
	}
	
	/** Sets the background color */
	public void clearBoard(Color color)
	{
		Player[][] state = game.getState();
		for(int i = 0; i < state.length; i++)
			for(int j = 0; j < state[i].length; j++)
				buttons[i][j].setBackground(color);
	}
	
	/** Disables buttons - used for when the AI is moving, or when the game ends */
	public void disableButtons()
	{
		for(int i = 0; i < buttons.length; i++)
			for(int j = 0; j < buttons[i].length; j++)
				buttons[i][j].setEnabled(false);
	}
	
	/** Enables buttons that are not occupied */
	public void allowMove()
	{
		Player[][] state = game.getState();
		for(int i = 0; i < state.length; i++)
			for(int j = 0; j < state[i].length; j++)
			{
				if(state[i][j] == Player.EMPTY)
					buttons[i][j].setEnabled(true);
			}
	}
}
